﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.IO.Compression;
using UMC.Data;
using UMC.Net;
using UMC.ITME.Entities;
using System.Collections.Generic;
using UMC.SshNet.Messages.Connection;
using System.Buffers;
using System.Net.Http.Headers;
using System.Net.Sockets;

namespace UMC.ITME
{
    public class DataFactory : IStringSubscribe
    {
        static DataFactory()
        {
            HotCache.Register<Site>("Root").Register("SiteKey");
            HotCache.Register<Cookie>("Domain", "user_id", "IndexValue").Register("user_id", "Domain", "IndexValue");
            HotCache.Register<SiteHost>("Host").Register("Root", "Host");
            HotCache.Register<SiteCert>("Domain");
            HotCache.Register<SiteGroup>("Key");
            HotCache.Register<Device>("Id").Register("Ip", "Id");
            HotCache.Register<Alert>("Id");
            HotCache.Register<Firewall>("Fingerprint");
            HotCache.Register<ProxySite>("Domain");
            HotCache.Register<Fingerprint>("Id", "UA");


            //
        }
        internal protected virtual bool CheckUser(StringValue configKey, StringValue userName, StringValue domain)
        {
            return true;
        }
        public static DataFactory Instance()
        {
            if (_Instance == null)
            {
                // InitFactory();
                _Instance = new DataFactory();
                NetSubscribe.Subscribe("SiteConfig", _Instance);
            }
            return _Instance;
        }
        static DataFactory _Instance;

        public virtual SiteGroup[] SiteGroup()
        {
            int index;
            return HotCache.Cache<SiteGroup>().Find(new Entities.SiteGroup(), 0, out index);

        }

        public virtual Site[] Site()
        {
            int index;
            return HotCache.Cache<Site>().Find(new Entities.Site(), 0, out index);

        }
        public virtual SiteGroup SiteGroup(int key)
        {
            return HotCache.Cache<SiteGroup>().Get(new ITME.Entities.SiteGroup { Key = key });

        }

        public virtual Alert[] Alert()
        {
            return HotCache.Cache<Alert>().Find(new Alert(), 0, out var _);//new ITME.Entities.Firewall { Fingerprint = p });//, "Fingerprint", new Guid[] { p2 });
        }
        public virtual Alert Alert(uint id)
        {
            return HotCache.Cache<Alert>().Get(new Alert() { Id = id });//, 0, out var _);//new ITME.Entities.Firewall { Fingerprint = p });//, "Fingerprint", new Guid[] { p2 });
        }
        public virtual void Put(Alert alert)
        {
            HotCache.Cache<Alert>().Put(alert);//new Alert() { Id = id });//, 0, out var _);//new ITME.Entities.Firewall { Fingerprint = p });//, "Fingerprint", new Guid[] { p2 });
        }

        // public virtual void Get(StringValue alert)
        // {
        //     HotCache.Cache<Alert>().Put(alert);//new Alert() { Id = id });//, 0, out var _);//new ITME.Entities.Firewall { Fingerprint = p });//, "Fingerprint", new Guid[] { p2 });
        // }
        public virtual Firewall Firewall(StringValue p)
        {
            return HotCache.Cache<Firewall>().Get(new ITME.Entities.Firewall { Fingerprint = p });//, "Fingerprint", new Guid[] { p2 });
        }
        public virtual Firewall[] Firewall(StringValue p, params StringValue[] strings)
        {
            return HotCache.Cache<Firewall>().Find(new ITME.Entities.Firewall { Fingerprint = p }, "Fingerprint", strings);//, "Fingerprint", new Guid[] { p2 });
        }
        public virtual Fingerprint Fingerprint(StringValue p, int userAgent)
        {
            return HotCache.Cache<Fingerprint>().Get(new ITME.Entities.Fingerprint { Id = p, UA = userAgent });//, "Fingerprint", new Guid[] { p2 });
        }
        public virtual Site Site(String root)
        {
            return HotCache.Cache<Site>().Get(new ITME.Entities.Site { Root = root });

        }
        public virtual Site Site(int siteKey)
        {
            return HotCache.Cache<Site>().Get(new ITME.Entities.Site { SiteKey = siteKey });

        }

        public virtual void Put(SiteGroup host)
        {
            HotCache.Cache<SiteGroup>().Put(host);
        }

        public virtual void Put(SiteHost host)
        {
            HotCache.Cache<SiteHost>().Put(host);
        }
        public virtual SiteHost Host(StringValue host)
        {
            return HotCache.Cache<SiteHost>().Get(new Entities.SiteHost { Host = host });
        }
        public virtual SiteHost[] Hosts(StringValue root)
        {
            int index;
            return HotCache.Cache<SiteHost>().Find(new Entities.SiteHost { Root = root }, 0, out index);
        }
        public virtual void Delete(SiteHost host)
        {
            HotCache.Cache<SiteHost>().Delete(host);
        }
        public virtual void Delete(Alert host)
        {
            HotCache.Cache<Alert>().Delete(host);
        }
        public virtual Cookie Cookie(String domain, Guid user_id, int index)
        {
            return HotCache.Cache<Cookie>().Get(new ITME.Entities.Cookie { Domain = domain, user_id = user_id, IndexValue = index });


        }
        public virtual Cookie[] Cookies(String domain, Guid user_id)
        {
            int index;
            return HotCache.Cache<Cookie>().Find(new Entities.Cookie { user_id = user_id, Domain = domain }, 0, out index);
        }
        public virtual void Put(Site site)
        {
            site.Root = site.Root.ToLower();
            HotCache.Cache<Site>().Put(site);
        }
        public virtual void Delete(Site site)
        {
            HotCache.Cache<Site>().Delete(site);
        }
        public virtual void Delete(Cookie cookie)
        {
            if (String.IsNullOrEmpty(cookie.Domain) == false && cookie.user_id.HasValue)
            {
                if (cookie.IndexValue.HasValue == false)
                {
                    cookie.IndexValue = 0;
                }
                HotCache.Cache<Cookie>().Delete(cookie);
            }
        }
        public virtual void Put(Cookie cookie)
        {
            if (cookie.IndexValue.HasValue == false)
            {
                cookie.IndexValue = 0;
            }
            if (String.IsNullOrEmpty(cookie.Domain) == false && cookie.user_id.HasValue)
            {
                HotCache.Cache<Cookie>().Put(cookie);
            }

        }
        public virtual Stream Decompress(Stream response, StringValue encoding)
        {
            if (encoding.Span.SequenceEqual("gzip"u8))
            {
                return new GZipStream(response, CompressionMode.Decompress);
            }
            else if (encoding.Span.SequenceEqual("deflate"u8))
            {
                return new DeflateStream(response, CompressionMode.Decompress);

            }
            else if (encoding.Span.SequenceEqual("br"u8))
            {

                return new BrotliStream(response, System.IO.Compression.CompressionMode.Decompress);
            }
            else
            {
                return response;
            }
        }

        public virtual Stream Compress(Stream response, StringValue encoding)
        {
            if (encoding.Span.SequenceEqual("gzip"u8))
            {

                return new GZipStream(response, CompressionMode.Compress);
            }
            else if (encoding.Span.SequenceEqual("deflate"u8))
            {
                return new DeflateStream(response, CompressionMode.Compress);
            }
            else if (encoding.Span.SequenceEqual("br"u8))
            {
                return new BrotliStream(response, System.IO.Compression.CompressionLevel.Fastest);
            }
            else
            {
                return response;
            }
        }
        Set<StringValue, SiteConfig> siteConfigs = new Set<StringValue, SiteConfig>((x, y) => x.Span.SequenceCompareTo(y.Span));
        // int siteSize = 0;
        public virtual SiteConfig SiteConfig(string root)
        {
            return SiteConfig(new StringValue(root));
        }
        public void Clear()
        {
            siteConfigs.Clear();
        }
        public virtual int RemoveWeight(String authority)
        {
            int count = 0;
            if (Net.NetProxy.Pool.TryGetValue(authority, out var pool))
            {
                if (pool.BurstError >= 10)
                {
                    var ls = siteConfigs.Span;
                    foreach (var cs in ls)
                    {
                        if (cs.Item2.RemoveWeight(authority))
                        {
                            count++;
                        }
                    }
                }
            }
            return count;
        }
        public virtual SiteConfig SiteConfig(StringValue root)
        {
            if (siteConfigs.TryGetValue(root, out var config) == false)
            {

                var site = this.Site(root.Span.UTF8());
                if (site != null)
                {
                    config = new SiteConfig(site);
                    lock (siteConfigs)
                    {
                        siteConfigs[root] = config;
                    }
                }
            }
            return config;
        }
        public virtual ReadOnlySpan<SiteConfig> SiteConfig()
        {
            return siteConfigs.Values;//.AsSpan(0, siteSize);
        }

        public virtual void Delete(SiteConfig siteConfig)
        {
            IStringSubscribe stringSubscribe = this;
            stringSubscribe.Subscribe(siteConfig.Root);
            NetSubscribe.Publish("SiteConfig", siteConfig.Root);

        }

        void IStringSubscribe.Subscribe(string message)
        {
            WebFactory.Auths.Remove(message);



            Utility.SyncClient(0x00, new StringValue(message));
            lock (siteConfigs)
            {
                siteConfigs.Remove(new StringValue(message));
            }
        }
    }
}
